from asyncio.windows_events import NULL
import json
from xml.dom.minidom import parse
import xml.dom.minidom
from enum import Enum


ids = [21208, 21210, 21209, 21216, 21296, 21213, 21214, 21228,21223,21227,21267,21241,21220,21212,21250,21218,21252,21269,21356]


###################
# define load json file
###################
def load_json_file(path):
  with open(path) as f:
    data = json.load(f)
  
  ids_count = {}
  for i in range(len(ids)):
    ids_count[ids[i]] = 0
  for i in range(len(data)):
    for j in range(len(ids)):
      if ids[j] == data[i]['id']:
        ids_count[ids[j]] += 1
  return ids_count, data

###################
# statistic protocal ids
# load json file to json_data structure
###################



ids = [21208, 21210, 21209, 21216, 21296, 21213, 21214, 21228,21223,21227,21267,21241,21220,21212,21250,21218,21252,21269,21356]
ids_count_all = {}
for i in range(len(ids)):
    ids_count_all[ids[i]] = 0
file_list =[]
strpath = "test"+str(2)+".json"
file_list.append(strpath)


dic_count, json_data = load_json_file(file_list[0])



for j in range(len(ids)):
   ids_count_all[ids[j]] += dic_count[ids[j]]
print("ids statistic: ",ids_count_all)




###################
# Spell /Card /Character defined for load xml files
###################
class Spell():
   id = 0
   name=""
   type=0
   type_desc=""
   gameautoAITarget = 0
   Zhanqi_Range = 0

 
class Card():
   id = 0
   name = ""
   type = 0
   subType = 0
   color = 0
   number = 0
   attRange = 0
   ZhanqiRange = 0
   attDistance = 0
   defDistance = 0
   spellId = 0
   cardsGroup = ""


class Character():
   id = 0
   name = ""
   exType = 0
   country = 0
   color = 0
   gender = 0
   hp = 0
   spellId1 = 0
   spellId2 = 0
   spellId3 = 0
   spellId4 = 0
   spellId5 = 0
   spellIds =[]

class Player():
   seat_id = -1
   char_id = -1
   country = -1
   my_name = ""
   my_char = NULL
   use_spell = []
   hand_cards = [] #手牌
   add_horse = -1 #+1马
   reduce_horse = -1 #-1马
   armor = -1 #护甲
   arms  = -1 #武器
   zb_cards = [] #装备卡
   giveup_cards = [] #弃牌卡
   out_cards =[] #出牌牌
   
   def __init__(self, seat_id, char_id, country):
      self.seat_id = seat_id
      self.char_id = char_id
      self.country = country
      self.my_char = Character()
      print("init player")
      return

   def update_char_info(self, character):
      self.my_char.id = character.id
      self.my_char.name = character.name
      self.my_char.exType = character.exType
      self.my_char.country = character.country
      self.my_char.color = character.color
      self.my_char.gender = character.gender
      self.my_char.hp = character.hp
      self.my_char.spellIds = []
      self.my_char.spellId1 = character.spellId1
      self.my_char.spellId2 = character.spellId2
      self.my_char.spellId3 = character.spellId3
      self.my_char.spellId4 = character.spellId4
      self.my_char.spellId5 = character.spellId5
      self.my_char.spellIds = character.spellIds
      print("update char info")
      self.my_name = self.my_char.name
      return

   def update_spell_info(self, spell):
      self.use_spell.append(spell)
      print(self.my_name, "use spell", spell.name)

   #str
   def update_opt_info(self, opt):
      print(self.my_name, "do opt: ", opt)


   def update_char_data(self,character):
      return


def check_int(value, revalue=0):
    if value is NULL:
        return revalue
    if value == "" or value == '':
        return revalue
    return int(value)
       


###################
# spells/cards/characters defined for data parse
###################
#这三个是配置信息加载模板 不要修改
dict_spells={}
dict_cards={}
dict_characters={}


################
#游戏模拟的全局信息
#会不断更新
max_seat_id = 7
my_seatid = 255
talbe_player_count =0
table_players = {}


###################
# load spell.xml
###################
DOMTree_spell = xml.dom.minidom.parse("spell.xml")
collection_spell = DOMTree_spell.documentElement


# 在集合中获取所有spell
spells = collection_spell.getElementsByTagName("spell")
print("load spell config, size:", len(spells))
for item in spells:
   ss = Spell()
   ss.id = check_int(item.getAttribute("id"))
   ss.name = item.getAttribute("name")
   ss.type = check_int(item.getAttribute("type"))
   ss.type_desc = item.getAttribute("type_desc")
   ss.gameautoAITarget = check_int(item.getAttribute("gameautoAITarget"))
   ss.Zhanqi_Range = check_int(item.getAttribute("Zhanqi_Range"))
   dict_spells[check_int(item.getAttribute("id"))] = ss


print(dict_spells[2].name)
print(dict_spells[2].type)


###################
# load playcard.xml
###################
DOMTree_card = xml.dom.minidom.parse("playcard.xml")
collection_card = DOMTree_card.documentElement


# 在集合中获取所有cards
cards = collection_card.getElementsByTagName("card")
print("load card config, size:",len(cards))
item_arr=["id", "name", "type", "subType", "color", "number", "attRange", "ZhanqiRange", "attDistance", "defDistance","spellId","cardsGroup" ]
for item in cards:
   cc = Card()
   cc.id = check_int(item.getAttribute("id"))
   cc.name = item.getAttribute("name")
   cc.type = check_int(item.getAttribute("type"))
   cc.subType = check_int(item.getAttribute("subType"))
   cc.color = check_int(item.getAttribute("color"))
   cc.number = check_int(item.getAttribute("number"))
   cc.attRange = check_int(item.getAttribute("attRange"))
   cc.ZhanqiRange = check_int(item.getAttribute("ZhanqiRange"))
   cc.attDistance = check_int(item.getAttribute("attDistance"))
   cc.defDistance = check_int(item.getAttribute("defDistance"))
   cc.spellId = check_int(item.getAttribute("spellId"))
   cc.cardsGroup = item.getAttribute("cardsGroup")
   dict_cards[cc.id] = cc


dict_cards[0] = Card()
print(dict_cards[3].name)
print(dict_cards[3].type)


###################
# load character.xml
###################
DOMTree_character = xml.dom.minidom.parse("character.xml")
collection_character = DOMTree_character.documentElement


# 在集合中获取所有characters
characters = collection_character.getElementsByTagName("character")
print("load character config, size:",len(characters))
item_arr=["id", "name", "exType", "country", "color", "gender", "hp", "spellId1", "spellId2", "spellId3","spellId4","spellId5" ]
for item in characters:
   _character = Character()
   _character.id = check_int(item.getAttribute("id"))
   _character.name = item.getAttribute("name")
   _character.exType = check_int(item.getAttribute("exType"))
   _character.country = check_int(item.getAttribute("country"))
   _character.color = check_int(item.getAttribute("color"))
   _character.gender = check_int(item.getAttribute("gender"))
   _character.hp = check_int(item.getAttribute("hp"))
   _character.spellId1 = check_int(item.getAttribute("spellId1"))
   _character.spellId2 = check_int(item.getAttribute("spellId2"))
   _character.spellId3 = check_int(item.getAttribute("spellId3"))
   _character.spellId4 = check_int(item.getAttribute("spellId4"))
   _character.spellId5 = check_int(item.getAttribute("spellId5"))
   _character.spellIds = []
   if _character.spellId1 > 0:
      _character.spellIds.append(_character.spellId1)
   if _character.spellId2 > 0:
      _character.spellIds.append(_character.spellId2)
   if _character.spellId3 > 0:
      _character.spellIds.append(_character.spellId3)
   if _character.spellId4 > 0:
      _character.spellIds.append(_character.spellId4)
   if _character.spellId5 > 0:
      _character.spellIds.append(_character.spellId5)
   #print("spell ids:", _character.spellIds)

   dict_characters[_character.id] = _character 

print(dict_characters[2].name)

#################################################################

# 注意 协议处理的参数都是整型
#      但是配置文件初始化加载的都是字符串型
#      协议处理时，部分参数从配置文件到游戏内存要先做一下从字符串到整形的格式转换

dict_game_model = {}

# 0(0-4) 1(5-9) 2(10-16) 3(17-25) 4(26-33) 5(34-41) 6(42-52) 7(53-60) 8(61-69) 9(70-85)
arr_game_model = ['','身份模式 8人局1个内奸', '身份模式 8人局2个内奸','身份模式 7人局1个内奸','身份模式 6人局1个内奸',\
            '身份模式 5人局1个内奸,普通场', '身份模式 5人局1个内奸,简易场','身份模式 9人局2个内奸','3V3选将','1V1选将',\
            '排位4v4', '1V1简单模式','高校联赛8人场','8人乱斗场','3V3人乱斗场','8人军争(神化再临)', '5人军争',\
            '虎牢关','副本','1v1铜钱场','3v3标准铜钱场','','', '新3v3模式', '练习场-5人无技能(全ai1)','天梯1v1场',\
            '天梯3v3场','天梯排位赛','国战','教学练习场','新1v1','身份场2人局','欢乐3v3明身份场','欢乐2v2明身份场',\
            '天梯新1v1场','ai 6人身份(全ai1)', '打年兽场1v3', '血战到底','抓鬼模式','战役模式','王战身份','王战3v3',\
            '王战1v1','王战血战','粮草模式','两人3v3','章节教学(全ai1)','新国战','','新手教学','比赛模式','雷达模式',' 手机欢乐1v1',\
            ' 手机2人教学场',' 手机5人训练场','手机2人训练场','手机教训模式','','手机斗地主','竞技场2v2',' 竞技场3v3',\
            ' 挑战赛',' 排位赛玩法的欢乐2v2','排位赛玩法的欢乐3v3','自建比赛','阵营战','自走棋','三军对决','幻化模式','巅峰排位赛',\
            '','','','','','国战群雄割据','','','','','','','5人国战 回归','','','国战演武场'\
]

for i in range(len(arr_game_model)):
   dict_game_model[i] = arr_game_model[i]

# print(dict_game_model)


# 协议处理
# protocal 21208
def func_userseat_ntf(msg):
   global talbe_player_count
   print("notify user seat info")
   game_model = msg["model"]
   print("游戏模式：", dict_game_model[game_model])
   my_seatid = msg["my_seatid"]
   print("myseat is: ",my_seatid)
   if len(msg["seatinfo"] )>0 :
      for i in range(len(msg["seatinfo"])):
         if msg["seatinfo"][i]["role_id"] > 0:
            print(msg["seatinfo"][i])
            talbe_player_count += 1
   for i in range(talbe_player_count):
      table_players[i] = Player(-1,-1,-1)
      table_players[i].my_char = Character()




# 协议处理
# protocal 21223
def func_show_figure(msg):
   print("figure info:",msg["seatid"], msg["figure"])

# 协议处理
# protocal 21216
def func_update_hp(msg):
   global dict_characters
   global table_players
   seatId = msg["seat_id"]
   if len(table_players) > 0 :
      print("seatid:", seatId, table_players[seatId].my_name,"update hp",  msg["hp"])
   else:
      print("update hp")

# 协议处理
# protocal 21227 
def func_set_character(msg):
   global dict_characters
   global table_players
   #四人2v2
   if msg["count"] >0:
      for i in range(msg["count"]):
         char_id = msg["character_info"][i]["char_id"]
         seat_id = msg["character_info"][i]["seat_id"]
         country = msg["character_info"][i]["country"]

         mychar = Player(seat_id, char_id, country)
         mychar.update_char_info(dict_characters[char_id])
         table_players[seat_id] = mychar
         print("set character: seat:", seat_id, dict_characters[char_id].name, "country:",country)

# 协议处理
"""
/////////////////////////////////spellid///////////////////////////////////////
杀(1)
data[0]:m_can_use 是否可以出杀
//隐藏部分
//data[1]:m_put_sha_cnt 用过杀的次数(本?睾?)
//data[2]:m_max_sha_times 最多能用的次数(本回合)

桃[3]
data[0]:m_can_use 是否可以出桃

仁德(31)
data[0]:m_give_card_cnt 已给的牌数

裸衣(50)
data[0]:m_luo_yi_state 是否裸衣状态

酒(82)
data[0]:m_b_jiu_state 是否喝了酒的状态

不屈(77)
data[0]:m_b_buqu_state 是否处于不屈状态

激将(32)
data[i]:m_bsha_by_jijiang[i] 能否对i座位号的role激将出杀

双雄(101)
data[0]:m_color 双雄判定后的颜色

涅槃(95)
data[0]:m_spell_use_times 是否使用过涅槃

天义(99)
data[0]:m_spell_use_times 是否使用过天义
data[1]:m_success 天义的使用结果

限定技
data[0]:m_spell_use_times 是否使用过限定技

opt id
	enum OptDataId
	{
		OPT_DATA_INVALID = 0,
		OPT_DATA_ADD_EX_SPELL,          //给role添加技能 data为spell id(袁术-伪帝)
		OPT_DATA_DEL_EX_SPELL,			//给role删除技能 data为spell id(断肠)
		OPT_DATA_IS_FIGURE_TAP,			//身份牌是否横置(public)
		OPT_DATA_IS_CHARCARD_TAP,       //武将牌是否横置(public)
		OPT_DATA_IS_CHARCARD_TURN_OVER, //武将牌是否翻面(public)
		OPT_DATA_REST,					//重整(public)
		OPT_DATA_LIMITED,				//限定技使用
		OPT_DATA_ADD_SPELL_EFFECT,		//增加技能效果
		OPT_DATA_REMOVE_SPELL_EFFECT,	//删除技能效果
		OPT_DATA_SET_CHARACTER_SPELL,	//设置武将有哪些技能
		OPT_ADD_HUA_SHEN_CARD,			//增加化身牌
		OPT_SET_HUA_SHEN_CARD,			//设置化身牌
		OPT_SET_CHARACTER_COUNTRY,		//设置武将国家
		OPT_SET_CHARACTER_GENDER,		//设置武将性别
		OPT_DATA_ADD_CHARACTER_SPELL_NEW, //给role添加技能 data[0]表示武将ID，为无效值时表示添加到角色，data[1]:添加的技能个数
		OPT_DATA_DEL_CHARACTER_SPELL_NEW, //给role删除技能 data[0]表示武将ID，为无效值时表示从角色身上删除; data[1]:删除的技能个数
		OPT_DATA_SET_CHARACTER_SPELL_NEW, //设置武将技能 data[0]表示武将ID，为无效值时表示设置的是玩家的技能;data[1]:技能个数
		OPT_DATA_SET_COMMON_HUAN_SHEN_CARD,//这一局中常用化身牌
		OPT_DATA_XIAO_BING,	//小兵状态
		OPT_DATA_STAR_PRIVILEGE,
		OPT_DATA_FU_LIN,	// 腹鳞牌
		OPT_DATA_DON_NOT_DISCARD_IN_DISCARD_PHASE,
		OPT_DATA_ROLE_COUNTRY_NTF,		//角色国籍，在分将之前
		OPT_DATA_LIMITED_RESET,         //限定技重置
		OPT_DATA_CANCEL_XIAO_BING,      //取消小兵
		OPT_DATA_MAX,					//ID的上限
	}

"""



dict_role_update_opt={}
opt_arr =["invalid opt", "add ex spell", "del ex spell", "is figure tap", "is characard tap", "reset", "limited", "add spell effect",\
   "remove spell effect", "set character spell", "add hua shen card", "set hua shen card", "set character country", "set character gender",\
      "add character spell new", "del character spell new", "set character spell new", "set common huashen card", "xiao bing", \
         "star privilege", "fu lin", "do not discard in discard phase", "role contry", "limited reset", "cancel xiao bing","opt max"]

for i in range(len(opt_arr)):
   dict_role_update_opt[i] = opt_arr[i]

print(dict_role_update_opt)

# protocal 21252
def func_role_data_ex(msg):
   seatId = msg["seat_id"]
   dataId = msg["data_id"]
   if msg["is_spell"] == True:
      #print(msg)
      ss = Spell()
      ss.id = dict_spells[dataId].id
      ss.name = dict_spells[dataId].name
      print(seatId, ss.id, ss.name)
      if len(table_players)>0:
         table_players[seatId].update_spell_info(ss)
   if msg["is_spell"] == False:
      if len(table_players)>0:
         sinfo = dict_role_update_opt[dataId]
         table_players[seatId].update_opt_info(sinfo)

   return


#protocal 21218
#
"""
	enum EmDataId	//就一个人,最多能背负的RoleData为7
	{
		DATA_INVALID = 0,
		DATA_CAN_USE_SHA,           //是否可以出杀 (不包括连弩和咆哮 client要自己检查)(public)
		DATA_IS_BUQU_STATE,         //是否在不屈状态(周泰-不屈)
		DATA_IS_FIGURE_TAP,         //身份牌是否横置(public)
		DATA_IS_CHARCARD_TAP,       //武将牌是否横置(public)
		DATA_IS_CHARCARD_TURN_OVER, //武将牌是否翻面(public)
		DATA_IS_JIU_STATE,          //是否在酒状态(public)
		DATA_DEAL_CARD_ADD,			//下个摸牌阶段额外摸牌数
		DATA_CAN_JI_JIANG_CNT,      //是否能用激将技能(刘备-激将)
		DATA_RAO_SHE_MARK,			//饶舌标记
		DATA_IS_LUO_YI_STATE,       //是否在裸衣状态(许褚-裸衣)
		DATA_SHUANG_XIOING_RESULT,	//双雄的结果(颜良文丑-双雄)
		DATA_TIAN_YI_RESULT,		//天义的结果(太史慈-天义)
		DATA_ADD_EX_SPELL,          //给role添加技能 data为spell id(袁术-伪帝)
		DATA_NIE_PAN,				//是否使用过涅槃
		DATA_DEL_EX_SPELL,          //给role添加技能 data为spell id(袁术-伪帝)
		DATA_MENG_YAN_FLAG,			//梦魇标志
		DATA_ADD_GAME_WAIT_TIME,	//游戏中 增加游戏等待时间的次数
		DATA_BAO_NU_FLAG,			//狂暴标记
		DATA_JIU_USE_TIMES,			//本回合内酒使用的次数
		DATA_SHAN_JIA_STATE,		//缮甲状态
		DATA_FLAG_REN,				//忍戒标记
		DATA_LIAN_JI_MARK,			//连技标记
		DATA_LONG_MARK,				//龙印
		DATA_FENG_MARK,				//凤印
		DATA_JU_MARK,				//"橘"标记
		DATA_XIN_TIANYI,			//[应该没用到]
		DATA_ZHEN_FA_ZHAO_HUAN_TIMES, //阵法召唤的次数
		DATA_BAO_LI,                //"暴戾"标记
		DATA_JUN_LUE_MARK,          //"军略"标记
		DATA_SHAN_JIA_NEW_STATE,    //新"缮甲"标记
		DATA_MARK_HOU_TU,           //后土
		DATA_MARK_ZI_WEI,           //紫薇            
		DATA_MARK_YU_QING,          //玉清
		DATA_MARK_GOU_CHEN,         //勾陈
		DATA_CAUSE_DAMAGE_HP_PLAY_PHASE, //出牌阶段造成的伤害
		DATA_YING_MARK,				//营
		DATA_FU_MARK,				//辅
		DATA_WUKU_MARK,				//武库
		DATA_YUFENG_MARK,			//御风
		DATA_MAX,					//ID的上限
		//不能超过255
	};
"""

dict_role_data={}
role_data_arr =["invalid data", "can use sha", "is buqu state", "figure tap",\
   "char card tap", "char card turn over", "jiu state", "deal card add", "can ji jiang count",\
   "rao she mark", "is luo yi state", "shuang xiong result","tian yi result", "add ex spell",\
   "nie pan", "del ex spell", "meng yan flag","add game wait time", "bao nu flag",\
   "jiu use times", "shan jia state","flag ren", "lian ji mark","long mark","feng mark",\
   "ju mark","xin tian yi","zhen fa call","bao li","jun lue","shan jia","mark hou tu",\
   "mark zi wei","mark yu qing","mark gou chen","cause damage hp in play phase","mark ying",\
   "mark fu","mark wuku","makr yufeng",\
   "data max"]

for i in range(len(role_data_arr)):
   dict_role_data[i] = role_data_arr[i]

print(dict_role_data)

def func_role_data(msg):
   seatId = msg["seat_id"]
   dataId = msg["data_id"]
   data = msg["data"]
   if len(table_players) > 0 :
      print("seatid:", seatId, table_players[seatId].my_name, dict_role_data[dataId]," value:", data)
   else:
      print("update role state, but need player info")

# optType 1 出牌 2 弃牌
def func_role_opt_phase(msg):
   seatId = msg["seat_id"]
   optType = msg["opt_type"] 
   param = msg["param"]  
   str_opt_phase = ["invalid", "出牌", "弃牌"]

   if len(table_players) > 0 :
      print("seatid:", seatId, table_players[seatId].my_name, str_opt_phase[optType]," value:", param)
   else:
      print("update role opt phase, but need player info")



def func_player_dead(msg):
   dead_seat_id = msg["dead_seat_id"]
   murder_seat_id = msg["murder_seat_id"]
   if len(table_players) > 0 and dead_seat_id != 255 and  murder_seat_id != 255:
      print("seatid:",dead_seat_id, table_players[dead_seat_id].my_name, "死了")
      print("seatid:",murder_seat_id, table_players[murder_seat_id].my_name, "是凶手")
   else:
      print("update player dead info, but need player info")   


def func_game_over(msg):
   print("game over")
   palyercount = msg["player_count"]
   str_result=["赢了","输了"]
   str_figure=["","主","忠","反","内","身份不明","身份不合法"]
   for i in range(palyercount):
      seatid = msg["game_result"][i]["seat_id"]
      result = msg["game_result"][i]["result"]
      figure = msg["game_result"][i]["figure"]
      name = table_players[seatid].my_name
      if result > 0:
         result = 1
      print(name, str_result[result], "身份:",str_figure[figure])
   print(msg)

def func_game_turn(msg):
   turn = msg["turn"]
   print("\ngame turn is:", turn,"----------------------------------------------------")


def func_use_spell(msg):
   #print(msg)
   if "spell_id" not in msg:
      return
   src_seat = msg["src_seat"]
   spell_id = msg["spell_id"]
   
   dest_count = msg["dest_count"]
   card_count = msg["card_count"]
   if len(table_players) > 0 :
      
      name = table_players[src_seat].my_name
      
      str_spell = dict_spells[spell_id].name
      str_dest_role =[]
      str_card_arr =[]
      for i in range(dest_count):
         dest_role = msg["datas"][i]
         str_dest_role.append(table_players[dest_role].my_name)
      for j in range(dest_count, dest_count+card_count):
         card_id = msg["datas"][j]
         str_card_arr.append(dict_cards[card_id].name)
      
      print(name, "发起技能", str_spell)
      print("技能目标玩家",str_dest_role, "使用了卡牌", str_card_arr)
   else:
      print("update use spell info, but need player info") 


"""

    PHASE_INIT = 0, //初始化
    PHASE_BEGIN,    //开始
    PHASE_JUDGE,    //判定
    PHASE_DEAL,     //发牌
    PHASE_PLAY,     //出牌
    PHASE_DISCARD,  //弃牌
    PHASE_END,      //结束
    PHASE_CLEARUP,  //清理
    PHASE_TURN_OVER,//全部结束，下一轮
    PHASE_MAX_CNT,
"""
def func_game_phase(msg):
   cur_seatid = msg["cur_seatid"]
   phase_id = msg["phase_id"]
   str_phase = ["初始化","开始","判定","发牌","出牌","弃牌","结束","清理","全部结束，进入下一轮","maxcnt"]

   if len(table_players) > 0 :
      print("seatid:",cur_seatid, table_players[cur_seatid].my_name, "进入",str_phase[phase_id])



"""
	enum EmOptType
	{
		OPT_INVALID = 0,
		OPT_SEL_COLOR,      //选择花色  dataCnt为1，data[0]为花色
		OPT_QUESTION,       //质疑      dataCnt为1，data[0]等于1时为质疑，为0时表示不质疑
		OPT_HUJIA,			//护驾
		OPT_GUHUO_RESULT,	//蛊惑结果(S->C)
		OPT_JIJIANG_RESULT,	//激将结果(S->C)
		OPT_GUANXING_RESULT,	//观星/心战结果(S->C)
		OPT_JUDGE_RESULT,	//判定结果(S->C)
		OPT_ERR,			//操作错误
		OPT_PINDIAN_RESULT,	//拼点结果
		OPT_JUDGE_CARD,		//(第一手)判定牌
		OPT_PINDIAN_CARD,	//已出拼点牌
		OPT_GUANXING_MOVECARD,	// 观星卡牌移动
		OPT_SHOW,			// 展示
		OPP_XINZHAN_RESULT,
		OPP_SPELL_EFFECT,	//技能效果生效
		OPP_SEL_TARGET_RESULT,//选择目标结果
		OPT_REFUSED_PIN_DIAN, //拒绝拼点
		OPT_WAIT_NEXT_WU_XIE,	//等待下个无懈可击触发
		OPT_FACE_UP_CHARACTER,	//亮将
		OPT_SHOW_CHARACTER,		//展示武将
		OPT_CANCEL_TRIGGER,		//不使用触发的技能
		OPT_SPELL_SEL,//技能操作的选择
		OPT_GETCARD_RESULT,		// 从XXX得到牌，可能是0张
		OPT_DOUDIZHU_ASK_MULTIPLE,		// 斗地主-询问叫倍数
		OPT_DOUDIZHU_CHOOSE_HP_CARD,	// 斗地主-农民死后询问另一农民回血或摸牌
		OPT_SPELL_OVER,
		OPT_SPELL_CANCEL_EFFECT,	//锦囊被取消效果（无懈）
		OPT_WIPE_RESULT,
		OPT_AI_ERROR = 29,			//AI响应错误 data[0]错误的协议号 data[1] 错误代码 
		OPT_SEL_NUM = 31,           //选择点数
		//OPT_GUESS_RESULT = 32,		//猜测结果
		OPT_MILITARYORDER_RESULT = 33,	//军令执行结果(S->C)
		OPT_SHOW_CHARACTER_NEW = 34,
		OPT_ENTER_FIERCE_BATTLE = 100, // 进入鏖战模式
		OPT_ENTER_PECULIAR_DAMAGE,	   // 进入特殊掉血	
		OPT_VIRTUAL_CARD_OVER,
		OPT_PRESENT_CARD,
		OPT_USE_CARD_FAIL,
	};

"""

str_opt_arr = ["invalid", "sel color", "hu jia", "guhuo result", "jijiang result", "guanxin result",\
          "judge result", "opt error", "pin dian result", "guanxin move card", "opt show", "xin zhan result", \
         "spell effect", "sel target result", "refuse pin dian", "wait next wuxie", "face up char", "show character", \
         "cancel trigger", "spell select", "get card result", "doudizhu ask nultiple", "doudizhu choose hp card", \
         "spell over", "spell cancel effect", "wipe result", "ai error","error", "sel num", "error", \
         "military order result", "show char new"  ]

dict_opt_arr_str ={}
for i in range(len(str_opt_arr)):
   dict_opt_arr_str[i] = str_opt_arr[i]
dict_opt_arr_str[100] = "enter fierce battle"
dict_opt_arr_str[101] = "enter peculiar damage"
dict_opt_arr_str[102] = "virtual card over"
dict_opt_arr_str[103] = "present card"
dict_opt_arr_str[104] = "use card fail"

def func_spell_opt_rep(msg):
   if msg["spell_id"] == 0:
      print("spell opt rep: error?", msg)
   seat_id = msg["seat_id"]
   opt_type = msg["opt_type"]
   spell_id = msg["spell_id"]
   data_count = msg["data_count"]
   if len(table_players) > 0 and seat_id != 255 :
      name = table_players[seat_id].my_name
      str_opt = dict_opt_arr_str[opt_type]
      if spell_id > 0:
         str_spell = dict_spells[spell_id].name
         print(name, "spell opt rep with ", str_spell," response:", str_opt )
      if data_count > 0:
         print("spell opt rep data size:", data_count, msg["data"])


class EmPosition(Enum):
    POS_FRONT_BOTTOM        = 0        #第一个位置，最底下的位置
    POS_CHEAT_TIP			= 1
    POS_BACK_TOP            = 65280   #最后的位置，最上面的位置
    POS_RANDOM              = 65281   #随机位置
    POS_NEEDLESS            = 65282   #无需指出

#movecard 
class eZoneType(Enum):
    ZONE_INVALID = 0
    ZONE_CARDPILE = 1    #摸牌堆
    ZONE_DISACARPILE = 2  #弃牌堆
    ZONE_STACK = 3        #堆叠区域
    ZONE_REMOVED = 4      #场外
    ZONE_HAND = 5        #手牌区
    ZONE_EQUIP = 6        #装备区
    ZONE_JUDGE = 7        #判定区
    ZONE_SPELL = 8         #技能使用的牌的区域，属于具体spell
    ZONE_SHUFFLE = 9		#洗牌区(只是告诉客户端,洗牌了或者牌堆的数量)
    ZONE_TEMP = 10			#临时区域,如交换时使用,从A区域到temp区域时会触发A失去事件, 从temp到B区域会触发B区域得到卡牌事件(此时卡牌在之前区域的信息不会更新)
    ZONE_DISCARD_BUFF = 11	#弃牌临时区域 客户端只是用来提示
    ZONE_VIRTUAL = 12		#虚拟区，用来存放一些特殊牌，如霹雳车。这个区域不属于任何角色或者技能
    ZONE_LOGIC_EX = 13      #游戏逻辑额外区域
    ZONE_END = 14			#结束

# protocal 21209
def func_move_card(jsdata):
    if jsdata['card_count'] == 160 or jsdata['data_count'] == 0 or jsdata['src_seat'] == 255 or jsdata['data'] == None :
        return
    cur_seat = jsdata['src_seat']
    #从1到5 从摸牌堆到手牌区 
    if jsdata['from_zone'] == eZoneType.ZONE_CARDPILE.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], " 摸牌： ", jsdata['data'], " spellId: ", jsdata['spell_id'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].hand_cards.append(_c)
    #从5到3 从手牌区到堆叠区域 
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_STACK.value:
        print(jsdata['from_id'],  "出牌： ", jsdata['data'])
        for _c in jsdata['data']:
            if _c in table_players[jsdata['from_id']].hand_cards:
               table_players[jsdata['from_id']].hand_cards.remove(_c)
               #增加到出牌的牌组
               table_players[jsdata['from_id']].out_cards.append(_c)
            else:
               print("从堆叠区域到 从5到3 remove error card=", _c, jsdata['from_id'])
    #从3到6 从堆叠区域到装备区 
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_EQUIP.value:
        print(jsdata['from_id'],  "装备牌： ", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].zb_cards.append(_c)
    #从5到5 从手牌区域到手牌区 
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], " 从 ", jsdata['from_id'], " 摸牌：", jsdata['data'])
        for _c in jsdata['data']:
            #目标添加手牌
            table_players[jsdata['to_id']].hand_cards.append(_c)
            #从玩家删除手牌
            if _c in table_players[jsdata['from_id']].hand_cards:
                table_players[jsdata['from_id']].hand_cards.remove(_c)
            else:
                print("从5到5 从手牌区域到手牌区 remove error", table_players[jsdata['from_id']].hand_cards , _c)
    #从3到2 从堆叠区域到弃牌区域 属于出牌 
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_DISACARPILE.value:
        print("从堆叠区域到弃牌区域 ", jsdata['data'])
    #从1到3 从摸牌堆到堆叠区域 从牌堆中摸出牌作为判定牌
    elif jsdata['from_zone'] == eZoneType.ZONE_CARDPILE.value and jsdata['to_zone'] == eZoneType.ZONE_STACK.value:
        print("从1到3 从摸牌堆到堆叠区域 屯田", jsdata['data'])
     #从3到5 从堆叠区域到手牌区 天妒 判定牌生效后，你就可以使用天妒技能获得那张使判定牌生效的牌。例如乐不思蜀
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], "从3到5 从堆叠区域到手牌区 ", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].hand_cards.append(_c)
    #从5到2 从手牌区到弃牌区 
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_DISACARPILE.value:
        print(jsdata['from_id'], "从5到2 从手牌区到弃牌区  ", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['from_id']].giveup_cards.append(_c)
    #从3到7 从堆叠区域到判定区
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_JUDGE.value:
        print("从堆叠区域到判定区 ", jsdata['data'])
    #从1到8 从摸牌区域到技能使用的牌的区域 属于具体spell 五谷丰登
    elif jsdata['from_zone'] == eZoneType.ZONE_CARDPILE.value and jsdata['to_zone'] == eZoneType.ZONE_SPELL.value:
        print("从摸牌区域到技能使用的牌的区域 属于具体spell ", jsdata['data'], " spell ", jsdata['spell_id'])
    #从8到5 从技能使用的牌的区域，属于具体spell 到手牌区
    elif jsdata['from_zone'] == eZoneType.ZONE_SPELL.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], "从技能使用的牌的区域 到手牌区  如五谷丰登 ", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].hand_cards.append(_c)
    #从7到2 判定区到弃牌区
    elif jsdata['from_zone'] == eZoneType.ZONE_JUDGE.value and jsdata['to_zone'] == eZoneType.ZONE_DISACARPILE.value:
        print("从7到2 判定区到弃牌区 ", jsdata['data'])
    #从6到2 装备区到弃牌区
    elif jsdata['from_zone'] == eZoneType.ZONE_EQUIP.value and jsdata['to_zone'] == eZoneType.ZONE_DISACARPILE.value:
        print(jsdata['from_id'], "从6到2 装备区到弃牌区 ", jsdata['data'], jsdata['from_id'],)
        for _c in jsdata['data']:
            if _c in table_players[jsdata['from_id']].zb_cards:
                table_players[jsdata['from_id']].zb_cards.remove(_c)
            else:
                print("从6到2 装备区到弃牌区 error 装备区没这种牌")
    #从6到5 装备区到手牌区
    elif jsdata['from_zone'] == eZoneType.ZONE_EQUIP.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], " 从 ",jsdata['from_id'], " 装备区到手牌区 ", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].hand_cards.append(_c)
            if _c in table_players[jsdata['from_id']].zb_cards:
                table_players[jsdata['from_id']].zb_cards.remove(_c)
            else:
                print("从6到2 装备区到弃牌区 error 装备区没这种牌")
    #从8到2 从技能使用的牌的区域，属于具体spell 到手牌区到弃牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_SPELL.value and jsdata['to_zone'] == eZoneType.ZONE_DISACARPILE.value:
        print("从8到2 从技能使用的牌的区域，属于具体spell 到手牌区到弃牌堆 ", jsdata['data'])
    #从3到3 从堆叠区域 到堆叠区域
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_STACK.value:
        print("从3到3 从堆叠区域 到堆叠区域 ", jsdata['data'])
    #从6到1 从装备区 到摸牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_EQUIP.value and jsdata['to_zone'] == eZoneType.ZONE_CARDPILE.value:
        print(jsdata['from_id'], "从6到1 从装备区 到摸牌堆", jsdata['data'])
        for _c in jsdata['data']:
            if _c in table_players[jsdata['from_id']].zb_cards:
                table_players[jsdata['from_id']].zb_cards.remove(_c)
            else:
                print("从6到2 装备区到弃牌区 error 装备区没这种牌")
    #从3到1 从堆叠区域 到摸牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_CARDPILE.value:
        print("从3到1 从堆叠区域 到摸牌堆 ", jsdata['data'])
    #从5到1 从手牌 到摸牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_CARDPILE.value:
        print(jsdata['from_id'], "从5到1 从手牌区 到摸牌堆  游戏开始免费换牌 ", jsdata['data'])
        for _c in jsdata['data']:
            #从玩家删除手牌
            if _c in table_players[jsdata['from_id']].hand_cards:
                table_players[jsdata['from_id']].hand_cards.remove(_c)
            else:
                print("从5到1 从手牌区 到摸牌堆  游戏开始免费换牌 remove error", table_players[jsdata['from_id']].hand_cards , _c)
    #从5到8 从手牌区 到技能使用的牌的区域，属于具体spell 惠民
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_SPELL.value:
        print(jsdata['from_id'], "从5到8 从手牌区 到技能使用的牌的区域 ", jsdata['data'])
        for _c in jsdata['data']:
            #从玩家删除手牌
            if _c in table_players[jsdata['from_id']].hand_cards:
                table_players[jsdata['from_id']].hand_cards.remove(_c)
            else:
                print("从5到8 从手牌区 到技能使用的牌的区域 remove error", table_players[jsdata['from_id']].hand_cards , _c)
    #从2到4 从弃牌堆到场外
    elif jsdata['from_zone'] == eZoneType.ZONE_DISACARPILE.value and jsdata['to_zone'] == eZoneType.ZONE_REMOVED.value:
        print("2到4 从弃牌堆到场外 ", jsdata['data'])
    #从4到3 从场外堆到堆叠区域
    elif jsdata['from_zone'] == eZoneType.ZONE_REMOVED.value and jsdata['to_zone'] == eZoneType.ZONE_STACK.value:
        print("从4到3 从场外堆到堆叠区域", jsdata['data'])
    #从2到2 从弃牌堆到弃牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_REMOVED.value and jsdata['to_zone'] == eZoneType.ZONE_REMOVED.value:
        print("2到2 从弃牌堆堆到从弃牌堆", jsdata['data'])
    #从2到5 从弃牌堆到手牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_REMOVED.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print("从2到5 从弃牌堆到从手牌堆", jsdata['data'])
        for _c in jsdata['data']:
            table_players[jsdata['to_id']].hand_cards.append(_c)
    #从6到3 从装备堆到堆叠区域
    elif jsdata['from_zone'] == eZoneType.ZONE_EQUIP.value and jsdata['to_zone'] == eZoneType.ZONE_STACK.value:
        print(jsdata['from_id'], " 从6到3 从装备堆到从堆叠区域 ", jsdata['data'])
        for _c in jsdata['data']:
            if _c in table_players[jsdata['from_id']].zb_cards:
                table_players[jsdata['from_id']].zb_cards.remove(_c)
            else:
                print("从6到3 从装备堆到从堆叠区域 error 装备区没这种牌")
    #从5到10 从手牌堆到临时区域,如交换时使用
    elif jsdata['from_zone'] == eZoneType.ZONE_HAND.value and jsdata['to_zone'] == eZoneType.ZONE_TEMP.value:
        print(jsdata['from_id'], " 从5到10 从手牌堆到临时区域,如交换时使用 ",jsdata['data'])
        for _c in jsdata['data']:
            #从玩家删除手牌
            if _c in table_players[jsdata['from_id']].hand_cards:
                table_players[jsdata['from_id']].hand_cards.remove(_c)
            else:
                print("从5到10 从手牌堆到临时区域,如交换时使用 remove error", table_players[jsdata['from_id']].hand_cards , _c)
    #从10到5 从临时区域,如交换时使用到手牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_TEMP.value and jsdata['to_zone'] == eZoneType.ZONE_HAND.value:
        print(jsdata['to_id'], "从10到5 从临时区域,如交换时使用到手牌堆 ", jsdata['data'])
        for _c in jsdata['data']:
            #从玩家删除手牌
            table_players[jsdata['to_id']].hand_cards.append(_c)
    #从2到1 从弃牌堆到摸牌堆
    elif jsdata['from_zone'] == eZoneType.ZONE_DISACARPILE.value and jsdata['to_zone'] == eZoneType.ZONE_CARDPILE.value:
        print("从2到1 从弃牌堆到摸牌堆 ",jsdata['data'])
    #从7到7 从判定堆到判定堆
    elif jsdata['from_zone'] == eZoneType.ZONE_JUDGE.value and jsdata['to_zone'] == eZoneType.ZONE_JUDGE.value:
        print("从7到7 从判定堆到判定堆 ",jsdata['data'])
    #从3到4 从堆叠区域堆到场外堆
    elif jsdata['from_zone'] == eZoneType.ZONE_STACK.value and jsdata['to_zone'] == eZoneType.ZONE_REMOVED.value:
        print("从3到4 从堆叠区域堆到场外堆 ",jsdata['data'])
    #从6到6 从装备区域堆到装备区堆
    elif jsdata['from_zone'] == eZoneType.ZONE_EQUIP.value and jsdata['to_zone'] == eZoneType.ZONE_EQUIP.value:
        print(jsdata['to_id'], "从6到6 从装备区域堆到装备区堆 ", jsdata['from_id'], jsdata['data'])
        for _c in jsdata['data']:
            #从玩家删除手牌
            table_players[jsdata['to_id']].zb_cards.append(_c)
            if _c in table_players[jsdata['from_id']].zb_cards:
                table_players[jsdata['from_id']].zb_cards.remove(_c)
            else:
                print("从5到10 从手牌堆到临时区域,如交换时使用 remove error", table_players[jsdata['from_id']].zb_cards , _c)
    else:
        print("move card error ", jsdata['from_zone'], jsdata['to_zone']) 

#使用牌
def func_use_card(jdata):
    out_str = ''
    if jdata['data'] != None:
        for id in jdata['data']:
            if len(table_players)>0:
               out_str += table_players[id].my_char.name
            if len(jdata['data']) > 1:
                out_str += "|"
    if len(table_players) > 0 :
      print(table_players[jdata['seat_id']].my_char.name," 对 ", out_str," 出卡牌 ", dict_cards[jdata['card_id']].name, '牌值=', jdata['card_id'])
    return

#游戏模拟
#game simulate
print("start game")
for i in range(len(json_data)):
   #print(json_data[i]["id"])
   opt_id = json_data[i]["id"] 
   sub_json_data = json_data[i]
   if opt_id == 21208:
      func_userseat_ntf(sub_json_data)
   if opt_id == 21223:
      func_show_figure(sub_json_data)
   if opt_id == 21216:
      func_update_hp(sub_json_data)
   if opt_id == 21227:
      func_set_character(sub_json_data)
   if opt_id == 21252:
      func_role_data_ex(sub_json_data)
   if opt_id == 21218:
      func_role_data(sub_json_data)
   if opt_id == 21214:
      func_role_opt_phase(sub_json_data)
   if opt_id == 21241:
      func_player_dead(sub_json_data)
   if opt_id == 21228:
      func_game_over(sub_json_data)
   if opt_id == 21296:
      func_game_turn(sub_json_data)
   if opt_id == 21212:
      func_use_spell(sub_json_data)
   if opt_id == 21213:
      func_game_phase(sub_json_data)
   if opt_id == 21220:
      func_spell_opt_rep(sub_json_data)
   if opt_id == 21210:#USE_CARD
      func_use_card(sub_json_data)
   elif opt_id == 21209:#MOVE_CARD
      func_move_card(sub_json_data)


